#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AbstractClass.Extensions;

namespace AbstractClass.Collections.Specialized
{
    /// <summary>
    /// Represents a list of <see cref="Predicate{T}"/> objects.
    /// </summary>
    /// <typeparam name="T">The type of the data associated with the predicates.</typeparam>
    public sealed class Conditions<T> : ICollection<Predicate<T>>
    {
        private readonly List<Predicate<T>> _conditionBase = new List<Predicate<T>>();

        #region ICollection<Predicate<T>> Members

        /// <summary>
        ///   Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        ///   A <see cref = "IEnumerator&lt;T&gt;" /> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<Predicate<T>> GetEnumerator()
        {
            return _conditionBase.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// Adds a predicate to the collection.
        /// </summary>
        /// <param name="item">A predicate item to add.</param>
        public void Add(Predicate<T> item)
        {
            _conditionBase.Add(item);
        }

        /// <summary>
        /// Clears this instance by removing all containing predicates.
        /// </summary>
        public void Clear()
        {
            _conditionBase.Clear();
        }

        /// <summary>
        /// Determines whether the <see cref="Conditions&lt;T&gt;"/> contains the specific predicate.
        /// </summary>
        /// <param name="item">The predicate to search in the <see cref="Conditions&lt;T&gt;"/>.</param>
        /// <returns>
        /// <c>true</c> if the specified predicate is found in the <see cref="Conditions&lt;T&gt;"/>; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(Predicate<T> item)
        {
            return _conditionBase.Contains(item);
        }

        void ICollection<Predicate<T>>.CopyTo(Predicate<T>[] array, int arrayIndex)
        {
            _conditionBase.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Removes a predicate from the <see cref="Conditions&lt;T&gt;"/>.
        /// </summary>
        /// <param name="item">The predicate to remove.</param>
        /// <returns>
        /// <c>true</c> if the specified predicate removed successfully; otherwise, <c>false</c>.
        /// </returns>
        public bool Remove(Predicate<T> item)
        {
            return _conditionBase.Remove(item);
        }

        /// <summary>
        /// Gets the total number of predicates in the <see cref="Conditions&lt;T&gt;"/>.
        /// </summary>
        public int Count
        {
            get { return _conditionBase.Count; }
        }

        bool ICollection<Predicate<T>>.IsReadOnly
        {
            get { return false; }
        }

        #endregion

        /// <summary>
        /// Determines whether the specified item satisfies all the conditions in the list.
        /// </summary>
        /// <param name="item">The item to verify.</param>
        /// <returns>
        /// <c>true</c> if the item satisfies all the conditions; otherwise, <c>false</c>.
        /// </returns>
        public bool AllSatisfiedBy(T item)
        {
            return _conditionBase.All(predicate => predicate.Invoke(item));
        }

        /// <summary>
        /// Determines whether the specified item satisfies none of the conditions in the list.
        /// </summary>
        /// <param name="item">The item to verify.</param>
        /// <returns>
        /// <c>true</c> if the item satisfies none of the conditions; otherwise, <c>false</c>.
        /// </returns>
        public bool NoneSatisfiedBy(T item)
        {
            return _conditionBase.All(predicate => !predicate.Invoke(item));
        }

        /// <summary>
        /// Determines whether the specified item satisfies at least one of the conditions in the list.
        /// </summary>
        /// <param name="item">The item to verify.</param>
        /// <returns>
        /// <c>true</c> if the item satisfies at least one of the conditions; otherwise, <c>false</c>.
        /// </returns>
        public bool AtLeastOneSatisfiedBy(T item)
        {
            return _conditionBase.Any(predicate => predicate.Invoke(item));
        }

        /// <summary>
        /// Gets the results of each conditions (in same order) when applied on the specified item.
        /// </summary>
        /// <param name="item">The item to verify.</param>
        /// <returns>
        /// A collection of Boolean values.
        /// </returns>
        public IEnumerable<bool> Results(T item)
        {
            return _conditionBase.Select(predicate => predicate.Invoke(item));
        }

        /// <summary>
        /// Gets a <see cref="Predicate&lt;T&gt;"/> which is equivalent to logical OR of all the predicates in the list.
        /// </summary>
        /// <returns>Logical OR of all the predicates.</returns>
        public Predicate<T> Ors()
        {
            Predicate<T> predicate = _conditionBase.FirstOrDefault();
            return _conditionBase.Aggregate(predicate, (current, item) => current.Or(item));
        }

        /// <summary>
        /// Gets a <see cref="Predicate&lt;T&gt;"/> which is equivalent to logical AND of all the predicates in the list.
        /// </summary>
        /// <returns>Logical AND of all the predicates.</returns>
        public Predicate<T> Ands()
        {
            Predicate<T> predicate = _conditionBase.FirstOrDefault();
            return _conditionBase.Aggregate(predicate, (current, item) => current.And(item));
        }
    }
}